package com.wyh.lotterysystem.service.impl;

import com.wyh.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import com.wyh.lotterysystem.common.exception.ServiceException;
import com.wyh.lotterysystem.common.utils.JacksonUtil;
import com.wyh.lotterysystem.common.utils.RedisUtil;
import com.wyh.lotterysystem.controller.request.DrawPrizeRequest;
import com.wyh.lotterysystem.controller.request.WinningRecordsRequest;
import com.wyh.lotterysystem.dao.dataobject.ActivityDo;
import com.wyh.lotterysystem.dao.dataobject.ActivityPrizeDo;
import com.wyh.lotterysystem.dao.dataobject.WinnerRecordDo;
import com.wyh.lotterysystem.dao.mapper.ActivityMapper;
import com.wyh.lotterysystem.dao.mapper.ActivityPrizeMapper;
import com.wyh.lotterysystem.dao.mapper.WinnerRecordMapper;
import com.wyh.lotterysystem.service.DrawPrizeService;
import com.wyh.lotterysystem.service.dto.WinningRecordsDTO;
import com.wyh.lotterysystem.service.enums.ActivityPrizeStatusEnum;
import com.wyh.lotterysystem.service.enums.ActivityStatusEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;

import static com.wyh.lotterysystem.common.config.DirectRabbitConfig.EXCHANGE_NAME;
import static com.wyh.lotterysystem.common.config.DirectRabbitConfig.ROUTING;

@Service
@Slf4j
public class DrawPrizeServiceImpl implements DrawPrizeService {

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    ActivityMapper activityMapper;

    @Autowired
    ActivityPrizeMapper activityPrizeMapper;

    @Autowired
    WinnerRecordMapper winnerRecordMapper;

    @Autowired
    RedisUtil redisUtil;

    private final Long WINNING_RECORDS_TIMEOUT = 60 * 60 * 24 * 2L;


    @Override
    public void drawPrize(DrawPrizeRequest request) {
        if (null == request){
            throw new ServiceException(ServiceErrorCodeConstants.DRAW_PRIZE_ERROR);
        }

        try {
            Map<String, String> map = new HashMap<>();
            map.put("message_id",String.valueOf(UUID.randomUUID()));
            map.put("message_data", JacksonUtil.writeValueAsString(request));
            rabbitTemplate.convertAndSend(EXCHANGE_NAME,ROUTING,map);

            //发送消息成功后直接返回。
            log.info("消息发送成功，map:{}", JacksonUtil.writeValueAsString(map));
        }catch (Exception e){
            throw new ServiceException(ServiceErrorCodeConstants.DRAW_PRIZE_ERROR);
        }
    }

    @Override
    public boolean checkDrawPrizeRequest(DrawPrizeRequest request) {
        if (null == request){
            log.warn("校验抽奖请求失败！失败原因：{}",
                    ServiceErrorCodeConstants.REQUEST_IS_EMPTY.getMsg());
            return false;
        }

        //检验活动是否存在
        ActivityDo activityDo = activityMapper.selectActivityById(request.getActivityId());
        if (null == activityDo) {
            log.warn("校验抽奖请求失败！失败原因：{}",
                    ServiceErrorCodeConstants.MESSAGE_ACTIVITY_IS_EMPTY.getMsg());
            return false;
        }

        //检验奖品是否存在
        ActivityPrizeDo activityPrizeDo = activityPrizeMapper.selectByActivityPrizeIdAndActivityId(request.getActivityId(),request.getPrizeId());
        if (null == activityPrizeDo) {
            log.warn("校验抽奖请求失败！失败原因：{}",
                    ServiceErrorCodeConstants.MESSAGE_ACTIVITY_PRIZE_IS_EMPTY.getMsg());
            return false;
        }

        //检验活动是否有效
        if (!activityDo.getStatus().equalsIgnoreCase(ActivityStatusEnum.RUNNING.name())){
            log.warn("校验抽奖请求失败！失败原因：{}",
                    ServiceErrorCodeConstants.MESSAGE_ACTIVITY_IS_EFFECTIVE.getMsg());
            return false;
        }

        //检验奖品是否有效
        if (!activityPrizeDo.getStatus().equalsIgnoreCase(ActivityPrizeStatusEnum.INIT.name())){
            log.warn("校验抽奖请求失败！失败原因：{}",
                    ServiceErrorCodeConstants.MESSAGE_ACTIVITY_PRIZE_IS_EFFECTIVE.getMsg());
            return false;
        }

        //检验中奖人数是否跟奖品数量一样
        if (request.getWinnerList().size() != activityPrizeDo.getPrizeAmount()){
            log.warn("校验抽奖请求失败！失败原因：{}",
                    ServiceErrorCodeConstants.MESSAGE_ACTIVITY_PRIZE_COUNT_ERROR.getMsg());
            return false;
        }

        return true;
    }

    @Override
    public List<WinningRecordsDTO> showRecords(WinningRecordsRequest request) {
        if (request == null){
            throw new ServiceException(ServiceErrorCodeConstants.SHOW_RECORDS_EMPTY);
        }

        String key = null == request.getPrizeId() ? String.valueOf(request.getActivityId())
                : request.getActivityId() + "_" + request.getPrizeId();


        //从redis中查找
        List<WinnerRecordDo> winnerRecordDos = getRecords(key);
        if (!CollectionUtils.isEmpty(winnerRecordDos)){
            return convertToWinningRecordsDTO(winnerRecordDos);
        }

        //从数据库中查找
        winnerRecordDos = winnerRecordMapper.selectByActivityIdAndPrizeId(request.getActivityId(),request.getPrizeId());

        if (CollectionUtils.isEmpty(winnerRecordDos)){
            log.warn("查询的中奖记录为空，request：{}", JacksonUtil.writeValueAsString(request));
            return List.of();
        }

        //缓存
        redisUtil.setRedisAndTime(key,JacksonUtil.writeValueAsString(winnerRecordDos),WINNING_RECORDS_TIMEOUT);

        return convertToWinningRecordsDTO(winnerRecordDos);
    }

    private List<WinningRecordsDTO> convertToWinningRecordsDTO(List<WinnerRecordDo> winnerRecordDos) {
        List<WinningRecordsDTO> winningRecordsDTOS = new ArrayList<>();
        winningRecordsDTOS = winnerRecordDos.stream()
                .map(winnerRecordDo -> {
                    WinningRecordsDTO winningRecordsDTO = new WinningRecordsDTO();
                    winningRecordsDTO.setWinnerId(winnerRecordDo.getWinnerId());
                    winningRecordsDTO.setWinningTime(winnerRecordDo.getWinningTime());
                    winningRecordsDTO.setWinnerName(winnerRecordDo.getWinnerName());
                    winningRecordsDTO.setPrizeName(winnerRecordDo.getPrizeName());
                    winningRecordsDTO.setPrizeTier(winnerRecordDo.getPrizeTier());
                    return winningRecordsDTO;
                })
                .toList();
        return winningRecordsDTOS;
    }

    private List<WinnerRecordDo> getRecords(String key) {
        try {
            if (!StringUtils.hasText(key)) {
                log.warn("要从缓存中查询中奖记录的key为空！");
                return Arrays.asList();
            }

            return JacksonUtil.readListValue(redisUtil.getValue(key), WinnerRecordDo.class);
        } catch (Exception e) {
            log.error("从缓存中查询中奖记录异常！key:{}", key);
            return Arrays.asList();
        }
    }
}
